#include "lom-value-factory.hh"
#include "lom-value.hh"
#include "lom-errors.hh"


namespace lom
{
    LomValueFactory::LomValueFactory( ILomInstanceManager* _mgr ) : mgr( _mgr ) 
    {
	valueCache.resize( EDataTypeLast );
    }
    LomValueFactory::~LomValueFactory()
    {
	setup( NULL );
    }

    static void deleteItem( LomValue* item ) 
    { 
	delete item; 
    }
    
    static void deleteVector( TValueVectorPair& pair ) 
    {
	do_all( pair.first, deleteItem );
	do_all( pair.second, deleteItem );
	pair.first.clear();
	pair.second.clear();
    }

    void LomValueFactory::setup( ILomInstanceManager* _mgr ) 
    { 
	reset();
	mgr = _mgr; 
    }
    void LomValueFactory::reset() {
	do_all( valueCache, deleteVector );
    }
    
    static LomValue* createNew( EDataType type, ILomInstanceManager* mgr )
    {
	switch( type )
	{	
	case EDataTypeBool:
	    return new LomBool();
	case EDataTypeString:
	    return new LomString();
	case EDataTypeStringV:
	    return new LomStringV();
	case EDataTypeHandle:
	    return new LomHandle(mgr);
	case EDataTypeHandleV:
	    return new LomHandleV(mgr);
	case EDataTypeDouble:
	    return new LomDouble();
	case EDataTypeDoubleV:
	    return new LomDoubleV();
	case EDataTypeInt64:
	    return new LomInt64();
	case EDataTypeInt64V:
	    return new LomInt64V();
	case EDataTypeDataV:
	    return new LomDataV();
	default:
	    throw UnrecognizedDatatype( type );
	}
	return NULL;
    }
    
    LomValue* LomValueFactory::create( EDataType type )
    {
	if ( type == EDataTypeNone )
	    return NULL;
	TValueVectorPair& dataPair = valueCache[type];
	if ( dataPair.first.empty() )
	    dataPair.first.push_back( createNew( type, mgr ) );
	LomValue* retval = dataPair.first.back();
	dataPair.first.pop_back();
	dataPair.second.push_back( retval );
	return dataPair.second.back();
    }
    
    void LomValueFactory::destroy( LomValue* value )
    {
	if ( !value )
	    return;
	TValueVectorPair& dataPair = valueCache[value->getDataType()];
	TValueVector::iterator find = std::find( dataPair.second.begin(), dataPair.second.end(), value );
	value->resetLomValue();
	//If this happens then the value wasn't allocated by this factory,
	//or it is begin dual-released.
	if ( find == dataPair.second.end() )
	    throw LomValueFactoryAllocationError();
	dataPair.second.erase( find );
	dataPair.first.push_back( value );
    }
}
